masterofmagicfandomcom-20200216-history
Talk:Casting Cost/@comment-2001:14BB:420:1D7B:E8FA:A1D6:E379:D063-20180702070218/@comment-1333593-20180704200940
@Tumu: Oops, I thought there was just the Sky Drake missing. Indeed, if there are two spells, they both need to be added. The amount of spells per book is exactly what is in the local static array where the overflow occurs (I could have given you those numbers). Seravy fixed the VRs both at the 2nd and 10th books, these are the first two bytes of W170. In theory, this by itself would have fixed the bug. Nonetheless, it's safer to fix the conditional jump too. I think that when this routine was written, it was assumed that it would only ever be called if there are still spells missing. In other words, if the book count is less than 10. The "error checking" is thus limited to aborting if there are exactly 10. This is the third byte of W170 ("Jump if not equal" changed to "Jump if less"). Because of the spell amount mismatch though, it is possible to have up to 2 missing Very Rares in the original game (and Insecticide). This triggers the branch that randomizes these, but of course only if there are not exactly 10 books possessed (which aborts the whole process). The stack frame of the function looks something like this (this is where all the local variables are): bp-$6A 20 bytes unknown spell selection list (1 word per spell, max 10, since there are only 10 per rarity) bp-$56 80 bytes spells per book array (1 word per rarity per book, i.e. 8 bytes per book) 06 2 bytes random roll result 04 2 bytes original book count 02 2 bytes loop counter bp 2 bytes previous stack pointer 02 4 bytes return address 06 2 bytes player index argument 08 2 bytes spellbook color argument Now, the spells per book array is set up hardcoded at the beginning of the routine. This is done so that this local array can be used as a counter, where the individual book/rarity element can be decremented when a spell is made knowable. And this is what is causing the bug at 11 or 12 books. You see, the addressing is linear, so "element 11" (indexing starts at 0, and runs to 9) of the array is 8 bytes after the beginning of "element 10" (which is skipped because of the "error checking"). I'm actually shocked that you only got one crash when setting the Common and Uncommon spells to Unknown, as this should be decrementing the return address. The most likely reason for not crashing is that when the game checks the array element to see if there are more spells to award, it uses a signed comparison. This is probably also why you can only get at most one Uncommon spell: the human player is always index 0, decrementing that to -1 always aborts the next cycle. It's also possible that you get memory corruption rather than an instant crash, which will not be apparent until later on. What's also important is that the actual books are only added to the profile at the end of this function, by incrementing the field where the color argument points to within the Spellbooks array of the wizard data. At 11 books, this will be overwritten and decremented to 0 by any Unknown Very Rare spells, meaning that it will always yield a Nature book in the profile. The only thing I didn't really figure out yet is how and why do you actually get some Nature spells to Research. That probably happens when you're awarded the second book. Unfortunately, as you can probably tell, I haven't really analyzed the function fully yet (it's tougher without a database), so I'll look at it some more as time allows. Until then, W170 can be used as a standalone (I'll probably just copy that into my own version too) =D PS: there should be no definitive counts for 11 and 12 books. In fact, at 12 books the values will come from the stack frame of the parent function (one of which will also be the spellbook color)...